package spoon.service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import spoon.core.domain.Game;
import spoon.core.exception.ConvertException;
import spoon.domain.WilliamhillGame;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

@Service
@Qualifier("williamhillFootballService")
public class WilliamhillFootballService extends WilliamhillAbstractService {

	@Resource(name = "williamhill.football.league")
	protected void getLeagueMap(Map<String, String> map) {
		this.leagueMap = map;
	}

	@Resource(name = "williamhill.football.team")
	protected void getTeamMap(Map<String, String> map) {
		this.teamMap = map;
	}

	@Value("#{williamhill['football.itemCode']}")
	protected void getItemCode(String itemCode) {
		this.ITEM_CODE = itemCode;
	}

	@Value("#{williamhill['football.itemName']}")
	protected void getItemName(String itemName) {
		this.ITEM_NAME = itemName;
	}

	@Value("#{williamhill['football.url']}")
	protected void getGateUrl(String url) {
		this.GATE_URL = url;
	}

	@Override
	public Elements getLeagueList() {
		log.info("===================================================================");
		log.info("    {} {} 리그 정보 검색 시작", SITE, ITEM_CODE);

		Elements elements = httpService.getElements(GATE_URL, ".listContainer > ul > li");
		// 첫번째는 제목이므로 제거한다.
		elements.remove(0);

		log.info("    {} {} 리그 정보 검색 종료. 전체 추가 리그수 = {}", SITE, ITEM_CODE, elements.size());
		log.info("===================================================================");

		return elements;
	}

	@Override
	@Async
	public void getLeague(Element element) {
		long startTime = System.currentTimeMillis();

		int leagueCnt = 0;
		int gameCnt = 0;
		int bettingCnt = 0;

		String nation = element.select("h3").text();
		Elements list = element.select("ul > li");

		for (Element li : list) {
			Game league = new Game();
			league.setSite(SITE);
			league.setUrl(URL);
			league.setItemName(ITEM_NAME);
			league.setItemCode(ITEM_CODE);
			league.setGameId(li.select("a").text());
			league.setNation(nation);
			league.setLeagueName(li.select("a").text());
			league.setLeagueCode(getLeagueCode(li.select("a").text()));
			league.setLink(li.select("a").attr("href"));

			this.getGameList(league);

			int gameSize = league.getGameList().size();
			gameCnt = gameCnt + gameSize;

			// 현재 진행 가능한 경기가 있다면
			if (gameSize > 0) {
				bettingCnt = bettingCnt + addBetting(league);
				leagueCnt++;
			} else {
				log.debug("진행 가능한 경기가 없다 국가: {}, 리그: {}, 링크 : {}", league.getNation(), league.getLeagueCode(), league.getLink());
			}

		}

		log.info("사이트: {}, 종목: {}, 국가: {}, 리그수: {}, 경기수: {}, 베팅수: {}, 소요시간: {}초", SITE, ITEM_CODE, nation, leagueCnt, gameCnt, bettingCnt,
				(System.currentTimeMillis() - startTime) / 1000.0f);
	}

	private void getGameList(Game league) {
		String source = httpService.getSource(league.getLink());

		Elements elements = Jsoup.parse(source).select("#tup_type_1");
		// #tup_type_1 이 없다면 현재 진행중인 리그가 아니다.
		if (elements.size() == 0) {
			log.debug("DIV #tup_type1 이 없음 정보 {}, {}, 링크 {}", league.getNation(), league.getLeagueCode(), league.getLink());
			return;
		}
		
		// 게임일자는 javascript로 해서 넣는다.
		Pattern p = Pattern.compile("push\\((\\{[^}]+\\})");
		Matcher m = p.matcher(source);

		Map<String, WilliamhillGame> map = new HashMap<String, WilliamhillGame>();
	
		while (m.find()) {
			try {
				WilliamhillGame g = new ObjectMapper().readValue(m.group(1).replaceAll("\\\\","'"), WilliamhillGame.class);
				map.put(g.getEvent_id(), g);
			} catch (JsonParseException | JsonMappingException e) {
				log.error("Williamhill Json Convert Error, {}, {}, {}, {}", league.getNation(), league.getLeagueCode(), league.getLink(), e.getStackTrace());
				log.error("원본소스: {}", source);
			} catch (IOException e) {
				log.error("Williamhill Json Convert Error, {}, {}, {}, {}", league.getNation(), league.getLeagueCode(), league.getLink(), e.getStackTrace());
			}
		}

		Elements trs = elements.first().select("tbody > tr");

		for (Element tr : trs) {
			// 유효성 체크
			String id = tr.attr("id");
			id = id.substring(id.lastIndexOf("_") + 1);

			WilliamhillGame gameInfo = map.get(id);

			if (gameInfo == null) {
				log.debug("script 가 없음 정보 {}, {}, 링크 {}", league.getNation(), league.getLeagueCode(), league.getLink());
				continue;
			}

			Elements tds = tr.select("td");

			Game game = new Game();

			// 날짜
			game.setGameDate(convertDate(gameInfo.getStart_time()));
			game.setLink(tds.get(2).select("a").attr("href"));
			// 팀명
			String[] teams = gameInfo.getEvent_name().split(" v ");
			if (teams.length != 2) {
				throw new ConvertException(new Throwable("팀명 변환 에러"));
			}
			game.setHomeTeamName(teams[0].trim());
			game.setHomeTeamCode(getTeamCode(teams[0].trim()));
			game.setAwayTeamName(teams[1].trim());
			game.setAwayTeamCode(getTeamCode(teams[1].trim()));

			// 승
			Game betting = new Game();
			betting.setBetTarget("Goals");
			betting.setBetTime("FT");
			betting.setBetType("1X2");
			betting.setBetName("Full Time Result");
			betting.setHandicap(0D);
			betting.setHandicapName("");
			betting.setBetRate(convertRate(tds.get(4).select(".eventprice").text()));
			betting.setBetRateName(game.getHomeTeamCode());
			betting.setBetRateCode("1");
			game.addGameList(betting);

			// 무
			betting = new Game();
			betting.setBetTarget("Goals");
			betting.setBetTime("FT");
			betting.setBetType("1X2");
			betting.setBetName("Full Time Result");
			betting.setHandicap(0D);
			betting.setHandicapName("");
			betting.setBetRate(convertRate(tds.get(5).select(".eventprice").text()));
			betting.setBetRateName("Draw");
			betting.setBetRateCode("X");
			game.addGameList(betting);

			// 패
			betting = new Game();
			betting.setBetTarget("Goals");
			betting.setBetTime("FT");
			betting.setBetType("1X2");
			betting.setBetName("Full Time Result");
			betting.setHandicap(0D);
			betting.setHandicapName("");
			betting.setBetRate(convertRate(tds.get(6).select(".eventprice").text()));
			betting.setBetRateName(game.getAwayTeamCode());
			betting.setBetRateCode("2");
			game.addGameList(betting);

			if (tds.size() > 7) {
				game.setLink(tds.get(7).select("a").attr("href"));
			} else {
				log.debug("정보 {}, {}, {}, {}, 테이블크기 {}, 링크: {}", league.getNation(), league.getLeagueCode(), game.getHomeTeamCode(), game.getAwayTeamCode(), tds.size(), league.getLink());
			}

			// 나머지 베팅들
			this.getBettingList(game);

			// 게임설정 완료
			if (game.getGameList().size() > 0) {
				league.addGameList(game);
			}
		}
	}

	// 추가 베팅
	private void getBettingList(Game game) {

		Elements elements = httpService.getElements(game.getLink(), ".marketHolderExpanded > table");
		
		for (Element table : elements) {
			String title = table.select("thead span").last().text();
			
			Map<String, String> map = new HashMap<String, String>();
			
			if ("First Half Double Chance".equals(title)) { // First Half Double Chance
				map.put("betTarget", "Goals");
				map.put("betTime", "1H");
				map.put("betType", "DC");
				map.put("betName", "First Half Double Chance");
				betDoubleChance(game, map, table);
			} else if ("Second Half Double Chance".equals(title)) { // Second Half Double Chance
				map.put("betTarget", "Goals");
				map.put("betTime", "2H");
				map.put("betType", "DC");
				map.put("betName", "Second Half Double Chance");
				betDoubleChance(game, map, table);
			} else if ("Draw No Bet".equals(title)) { // Draw No Bet
				betDrawNoBet(game, table);
			} else if ("Match Handicaps".equals(title)) { // Match Handicaps
				betMatchHandicap(game, table);				
			} else if ("Double Chance".equals(title)) { // Double Chance
				map.put("betTarget", "Goals");
				map.put("betTime", "FT");
				map.put("betType", "DC");
				map.put("betName", "Double Chance");
				betDoubleChance(game, map, table);
			} else if ("1st Half Betting".equals(title)) { // 1st Half Betting
				map.put("betTarget", "Goals");
				map.put("betTime", "1H");
				map.put("betType", "1X2");
				betMatch(game, map, table);
			} else if ("2nd Half Betting".equals(title)) { // 2nd Half Betting
				map.put("betTarget", "Goals");
				map.put("betTime", "2H");
				map.put("betType", "1X2");
				betMatch(game, map, table);
			} else if ("Total Match Goals Under/Over".equals(title)) { // Total Match Goals Under/Over
				map.put("betTarget", "Goals");
				map.put("betTime", "FT");
				map.put("betType", "OU");
				map.put("betName", "Total Match Goals Under/Over");
				betOverUnder(game, map, table);
			}
		}

	}

}
